/*
 * FunnelDeque.h
 *
 *  Created on: 16/08/2012
 *      Author: Aeradon
 */

#ifndef FUNNELDEQUE_H
#define FUNNELDEQUE_H

#include <stdlib.h>
#include <math.h>
#include <list>

#include "PFRUtils.hpp"
#include "point.hpp"
#include "Polygon.h"
#include "../include/Vector2D.h"
#include "FunnelNode.h"

class NaviNode;

//#ifdef _BUILD_DLL
//   #define DLLDIR  __declspec(dllexport)   // export DLL information
//#else
//   #define DLLDIR  __declspec(dllimport)   // import DLL information
//#endif
//
//class DLLDIR FunnelDeque
class FunnelDeque
//the funnel deque used in the funnel algorithm
{
private:
	typedef float T;

public:
	//different kinds of corners - point, left and right tangent
	//(tangent to a circle around the corner, running along the side specified)
	enum CORNER_TYPE
	{
		POINT,
		LEFT_TANGENT,
		RIGHT_TANGENT
	};

protected:
	//left end, right end, and apex pointers for the deque
	FunnelNode *nLeft;
	FunnelNode *nRight;
	FunnelNode *nApex;

	//the corner type of the node at the apex
	//(ones on the left side are all right tangent, ones on the right are all left tangent)
	CORNER_TYPE m_tApexType;
	//radius of the unit for which we are finding the path
	float m_dRadius;
	//angle between the first and second points given their corner types
	float Angle(float x_1, float y_1, CORNER_TYPE type_1, float x_2, float y_2, CORNER_TYPE type_2);
	//constrains an angfle to the range (-PI, PI]
	float AngleRange(float theta);
	//returns the (Euclidean) distance between two points
	float Distance(float x_1, float y_1, float x_2, float y_2);
	//returns the angle between the given points
	//(same as the angle to their tangents if they're the same type)
	float ToTangent(float x_1, float y_1, float x_2, float y_2);
	//returns the angle between tangents of the given points
	//given whether the first is left tangent type, assuming the second is the opposite
	float ToTangentAlt(float x_1, float y_1, float x_2, float y_2, bool LeftRight);
	//returns the angle between the first point and a tangent to the second
	//(the type of the second is specified)
	float PointToTangent(float x_1, float y_1, float x_2, float y_2, bool Right);
	//adds a given point to the path
	void AddPoint(float x, float y, CORNER_TYPE type, float angle, Polygon2D<T> &path);
	void AddVec2D(float x, float y, CORNER_TYPE type, float angle, std::list<Vector2D>* path);
public:
	//creates the funnel deque based on a starting point and radius
	FunnelDeque(float x, float y, float r);
	//copy constructor
	FunnelDeque(const Point<T>& point, float r);
	//destructor
	~FunnelDeque();
	//adds a given point of a given type to the funnel deque, adding to the path if necessary
	void Add(const Point<T>& p, CORNER_TYPE type, Polygon2D<T>& path);
	void Add(const Vector2D& v, CORNER_TYPE type, std::list<Vector2D>* path);
	//calculates the length of the path for a unit of given radius
	float Length(Polygon2D<T> path);

	//prints the contents of the funnel deque
	void PrintFunnel();
	//prints the contents of the path
	void PrintPathAndFunnel(std::list<Vector2D>* path);
};

#endif

//definition of FunnelDeque class }
